﻿using Albatross.WPF.Common.PubSub;
using Albatross.WPF.Common.ViewModels;
using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;

namespace Albatross.WPF.Common.Views{
	public class CompositeViewService : DependencyObject, IViewService {
		static int Count;
		public int ID { get; set; }
		
		public CompositeViewService() {
			ID = Count;
			Count++;
		}


		public const string Region_Shell = "Shell";
		
		FrameworkElement _parent;
		Dictionary<string, ContentControl> _regions = new Dictionary<string, ContentControl>();

		public void LoadElement(UIElement elem) {
			if (_parent == null) {
				if (elem is FrameworkElement) {
					_parent = (FrameworkElement)elem;
				} else {
					throw new ArgumentException("CompositeViewService has to be attached to an FrameworkElement");
				}
			}
			if (elem is ContentControl) {
				string region = Convert.ToString(elem.GetValue(Attached.CompositeRegionProperty));
				if (!string.IsNullOrEmpty(region)) {
					_regions[region] = (ContentControl)elem;
					//set the region data context to null by default. otherwise, view service wouldn't know whether to dispose the content control
					//also, we should do this to avoid accidental binding.
					((ContentControl)elem).DataContext = null;
				}
			}
		}

		public void UnloadElement(UIElement elem) {
			if (elem is ContentControl) {
				string region = Convert.ToString(elem.GetValue(Attached.CompositeRegionProperty));
				if (_regions.ContainsKey(region) && _regions[region] == elem) {
					_regions.Remove(region);
				}
			}
		}

		public IPublisher Publisher { get { return ShellViewService.Publisher; } }

		IViewService ShellViewService {
			get {
				if (_parent != null) {
					Window win = Window.GetWindow(_parent);
					if (win != null) {
						IViewService svcs = (IViewService)win.GetValue(Attached.ViewServiceProperty);
						if (svcs != null) { return svcs; }
					}
				}
				throw new ViewServiceNotAvailableException();
			}
		}

		
		public const string DefaultRegionPropertyName = "DefaultRegion";
		public static readonly DependencyProperty DefaultRegionProperty = DependencyProperty.Register(DefaultRegionPropertyName, typeof(string), typeof(CompositeViewService), new PropertyMetadata());
		public string DefaultRegion {
			get { return (string)GetValue(DefaultRegionProperty); }
			set { SetValue(DefaultRegionProperty, value); }
		}

		public void ShowWorkspace(IWorkspaceConstruct construct) {
			if (construct.Region == null) { construct.Region = DefaultRegion; }
			if (string.IsNullOrEmpty(construct.Region) || construct.Region == Region_Shell) {
				ShellViewService.ShowWorkspace(construct);
			} else {
				if (_regions.ContainsKey(construct.Region)) {
					ContentControl region = _regions[construct.Region];
					try {
						if (ViewServiceExt.TryCloseView(region)) {
							if (!construct.IsEmpty()) {
								region.SetValue(Attached.WorkspaceConstructProperty, construct);
								region.Content = construct.GetView();
								region.DataContext = construct.Build();
								if (construct.Constructed.AsyncLoadHandler != null) {
									construct.Constructed.AsyncLoadHandler(this);
								}
							}
						}
					} catch (Exception err) {
						ShowErrorMessageBox(err.Message);
					}
				}
			}
		}

		public bool CloseWorkspace(IWorkspaceViewModel vm) {
			if (vm == _parent.DataContext) {	//closing the whole composite view
				return ShellViewService.CloseWorkspace(vm);
			} else {
				//try to find the content control
				try {
					foreach (ContentControl region in _regions.Values) {
						if (region.DataContext == vm) {
							return ViewServiceExt.TryCloseView(region);
						}
					}
				} catch (Exception err) {
					ShowErrorMessageBox(err.Message);
					return false;
				}
			}
			return false;
		}

		public bool? ShowDialog(IWorkspaceConstruct construct, int? width, int? height) {
			return ShellViewService.ShowDialog(construct, width, height);
		}

		public void CreateWindow(IWorkspaceConstruct construct) {
			ShellViewService.CreateWindow(construct);
		}

		public void ShowWarningMessageBox(string msg) {
			ShellViewService.ShowWarningMessageBox(msg);
		}

		public void ShowErrorMessageBox(string msg) {
			ShellViewService.ShowErrorMessageBox(msg);
		}

		public void ShowInfoMessageBox(string msg) {
			ShellViewService.ShowInfoMessageBox(msg);
		}

		public bool ShowConfirmationMessageBox(string msg) {
			return ShellViewService.ShowConfirmationMessageBox(msg);
		}
	}
}
